using System;
using System.Collections.Generic;
using System.Text;

using System.Data;
using System.Windows.Forms;
using System.Diagnostics;
using Microsoft.AnalysisServices.AdomdClient;

namespace BILab.Technical.BI.Facade
{
    


    public class MultidimensionalFacade : BILab.Technical.BI.Facade.IMultidimensionalFacade 
    {

        #region Facade properties and fields
        private string _connectionString;
        private AdomdConnection _mdConn;
        /// <summary>
        /// Server connection string
        /// </summary>
        public string ConnectionString
        {
            get { return _connectionString; }
            set { _connectionString = value; }
        }
        #endregion

        #region Facade Querying Methods
        /// <summary>
        /// Runs a MDx Query and returns a dataset
        /// </summary>
        public DataSet getDataset(string  mdxQuery)
        {
            DataSet  ds = new DataSet();

            AdomdCommand  cmd = new AdomdCommand( mdxQuery, _mdConn);
            AdomdDataAdapter  adpt = new AdomdDataAdapter( cmd);
            int nbOfRows =  adpt.Fill( ds);
            return  ds;
        }

        /// <summary>
        /// Runs a MDx Query and returns a cellset
        /// </summary>
        public CellSet getCellSet(string  mdxQuery)
        {
            CellSet  cs;
            AdomdCommand  cmd = new AdomdCommand( mdxQuery, _mdConn);
             cs =  cmd.ExecuteCellSet();

            return  cs;
        }


        
        #endregion

        #region Dimension treenode management
        /// <summary>
        /// Returns a treenode to represent DimensionTree
        /// </summary>
        public TreeNode GetDimensionTree(string  cubeName)
        {
            TreeNode  nodes = new TreeNode("Dimension");
            string dimName;
            // Step 1
            List<string> dim = this.getDimension(cubeName);

            // Step 2
            for (int i = 0; i < dim.Count; i++)
            {
                dimName = dim[i];
                TreeNode dimNode = new TreeNode(dimName,1,1);                

                /* populates hierarchies for a given dimension*/
                // Step 3
                this.getHierarchyTree(ref dimNode, cubeName, dimName);

                /* populates Hierarchy list */               
                nodes.Nodes.Add(dimNode);
            }
            return  nodes;
        }

        /// <summary>
        /// Returns a treenode to represent a hierarchy tree for a given dimension
        /// </summary>
        private void getHierarchyTree(ref TreeNode r_parentNode, string  cubeName, string  DimName)
        {
           //Step 1
           List<string>  hier = this.getHierarchies( cubeName,  DimName);

            string hierName;

            // Step 2
            for (int i = 0; i < hier.Count; i++)
            {
                hierName = hier[i];
                TreeNode hier_node = new TreeNode(hierName,2,2);

                // Step 3
                /* populates the levels for that given hierarchy */
                this.getLevelTree(ref hier_node, cubeName, DimName, hierName);

                // Step 4
                r_parentNode.Nodes.Add(hier_node);
            }
        }

        /// <summary>
        /// Returns a treenode to represent level tree for a given hierarchy
        /// </summary>
        private void getLevelTree(ref TreeNode r_parentNode, string  cubeName, string  dimName, string  hierName)
        {
            // step 1
            List<string>  level = this.getLevels( cubeName,  dimName,  hierName);

            string levelName;
            // Step 2
            for (int i = 0; i < level.Count; i++)
            {
                levelName = level[i];
                TreeNode tempNode = new TreeNode(levelName,3,3);
                tempNode.Nodes.Add("dummy");
                // Step 3
                //this.getMemberTree(ref tempNode, cubeName, dimName, hierName, levelName);

                // Step 4
                r_parentNode.Nodes.Add(tempNode);
            }
        }

        public void getMemberTree(ref TreeNode r_parentNode, string cubeName, string dimName, string hierName, string levelName)
        {
            List<string> members = this.getMembers(cubeName, dimName, hierName, levelName);
            string memberName;

            for (int i = 0; i < members.Count; i++)
            {
                memberName = members[i];
                TreeNode tempNode = new TreeNode(memberName,4,4);
                r_parentNode.Nodes.Add(tempNode);
            }
        }

        #endregion

        #region Cube Metadata "conversion"


        /// <summary>
        /// Returns the cube list
        /// </summary>
        public List<string> getCubeList()
        {
            /* gets the number of cubes */
            int nbOfCubes = _mdConn.Cubes.Count;
            List<string> cubeList = new List<string>();


            /* iterates into the cube list and load a global List */
            for (int i = 0; i < nbOfCubes; i++)
            {
                CubeDef cube = _mdConn.Cubes[i];

                /* We filter because cubes, dimensions ... are exposed at the same level */
                if (cube.Type == CubeType.Cube)
                {
                    cubeList.Add(_mdConn.Cubes[i].Name);
                }
            }
            return cubeList;
        }

                /// <summary>
                /// Returns dimension list of a cube (called by GetDimensionTree)
                /// </summary>
        public List<string> getDimension(string  cubeName )
        {
            List<string> list = new List<string>();
            CubeDef  cube = this._mdConn.Cubes[ cubeName];

            int cnt = cube.Dimensions.Count;           
                for (int i = 0; i < cnt; i++)
                {
                    list.Add(cube.Dimensions[i].Name);
                }
            return  list;
        }

                /// <summary>
                /// Returns dimension list of a cube, a given dimension (called by getHierarchies)
                /// </summary>
        public List<string> getHierarchies(string cubeName, string dimName)
        {
            List<string> list = new List<string>();
            Dimension dim = this._mdConn.Cubes[cubeName].Dimensions[dimName];

            int cnt = dim.Hierarchies.Count;
            for (int i = 0; i < cnt; i++)
            {

                list.Add(dim.Hierarchies[i].Name);

            }
            return list;
        }

                /// <summary>
                /// Returns a level list (called by getLevelTree)
                /// </summary>
        public List<string> getLevels(string cubeName, string dimName, string hierName)
        {
            List<string> list = new List<string>();
            Hierarchy hier = this._mdConn.Cubes[cubeName].Dimensions[dimName].Hierarchies[hierName];

            int cnt = hier.Levels.Count;

            for (int i = 0; i < cnt; i++)
            {
                list.Add(hier.Levels[i].Name);
            }
            return list;
        }

        public List<string> getMembers(string cubeName, string dimName, string hierName, string levelName)
        {
            List<string> list = new List<string>();
            Level lev = this._mdConn.Cubes[cubeName].Dimensions[dimName].Hierarchies[hierName].Levels[levelName];
            foreach (Member member in lev.GetMembers())
            {
                list.Add(member.Name);
            }
            return list;
        }       

        #endregion

        #region Cube Connectivity
        /// <summary>
        /// Open internally a connection to OLAP Server
        /// </summary>
        private ConnectionState connect(string connString )
        {

            this.ConnectionString = connString;
            _mdConn = new AdomdConnection(this.ConnectionString);
            _mdConn.Open();
            return _mdConn.State;

        }

        /// <summary>
        /// Open internally a connection and give a status
        /// </summary>
        public Boolean Connect(string connString)
        {
            Boolean connected = false;
            this.ConnectionString = connString;
            _mdConn = new AdomdConnection(this.ConnectionString);
            _mdConn.Open();
            if (_mdConn.State == ConnectionState.Open)
            {
                connected = true;
            }
            return connected;
        }

        /// <summary>
        /// Close the server connection
        /// </summary>
        public void Close()
        {
            if (_mdConn != null)
            {
                if (_mdConn.State == ConnectionState.Open)
                {
                    _mdConn.Close();
                }
            }
            
        }

        #endregion

    }
}
